10.10 固有的不可移植的特性

简介

为了支持低层编程,C++定义了一些固有的不可移植的特性。所谓不可移植的特性是指因机器而异的特性,当我们将不可移植特性的程序从一台机器转移到另一台机器上时,通常需要重新编写该程序。算术类型的大小在不同机器上不一样,这是我们使用过的不可移植特性的一个典型示例。

位域

类可以将其(非静态)数据成员定义成位域bit-field,在一个位域中含有一定数量的二进制位。当一个程序需要向其他程序或者硬件设备传递二进制数据时,通常会用到位域。

Tips:位域在内存中的布局是与机器相关的。

位域的类型必须是整型或者枚举类型。因为带符号位域的行为是由具体实现确定的,所以在通常情况下我们使用无符号类型保存一个位域。位域的声明形式是在成员名字之后紧跟一个冒号以及一个常量表达式,该表达式用于指定成员所占的二进制位数:

typedef unsigned int Bit;
class File {
    Bit mode: 2;         // mode占两位
    Bit modified: 1;     // modified占1位
    Bit prot_owner: 3;   // 占3位
    Bit prot_group: 3;   // 占3位
    Bit prot_world: 3;   // 占3位
 public:
    // 文件以八进制的形式表示
    enum modes { READ = 01, WRITE = 02, EXECUTE = 03 };
    File &opne(modes);
    void close();
    void write();
    bool isRead() const;
    void setWrite();
};
  • 如果可能的话,在类的内部连续定义的位域液压锁在同一整数的相邻位,这意味着前面五个位域可能会存储在一个unsigned int中,这些二进制位能否压缩到一个整数中以及如何压缩是与机器相关的

  • 取地址运算符&不能作用域位域,因此任何指针都无法指向类的位域

  • 最好将位域设为无符号类型,存储在带符号类型中的位域的行为将因具体实现而定

volatile限定符

直接处理硬件的程序通常包含这样的数据元素,它们的值由程序直接控制之外的过程控制。例如程序可能包含一个由系统时钟定时更新的变量。当对象的值可能在程序的控制或检测之外被改变时,应该将该对象声明为volatile,告诉编译器不应对这样的对象进行优化。

// 该int值可能发生改变
volatile int display_register;

链接指示: extern "C"

C++程序有时候需要调用其他语言编写的函数(比如C语言)。其他语言中的函数名字也必须在C++中进行声明,并且该声明必须指定返回类型和形参类别。对于其他语言编写的函数来说,编译器检查其调用的方式与处理普通C++函数的方式相同,但是生成的代码有所区别。C++使用链接指示指出任意非C++函数所用的语言。

1. 声明一个非C++函数

// cstring头文件中C函数的声明
// 单语句链接指示
extern "C" size_t strlen(const char *);
// 复合语句链接指示
extern "C" {
	int strcmp(const char*, const char*);
	char *strcat(char*, const char*);
}

2. 链接指示与头文件

// 复合语句链接指示
extern "C" {
#include <string.h>  // 操作C风格字符串的C函数
}

上面的写法意味着头文件中所有普通函数声明都被认为是由链接指示的语言编写的。

3. 指向extern "C"函数的指针

// pf指向一个C函数, 该函数接受一个int返回void
extern "C" void (*pf)(int);

Tips:指向C函数的指针和指向C++函数的指针是不一样的类型

4. 链接指示对整个声明都有效

当我们使用链接指示时,它不仅对函数有效,而且对作为返回类型或形参类型的函数指针也有效。

// f1是一个C函数, 它的形参是一个指向C函数的指针
extern "C" void f1(void(*)(int));

5. 导出C++函数到其他语言

通过链接指针对函数进行定义,我们可以令一个C++函数在其他语言编写的程序中可用:

// calc函数可以被C程序调用
extern "C" double calc(double dparm) { /*...*/) }

6. 重载函数与链接指示

C语言不支持函数重载,因为也就不难理解一个C链接指示只能用于说明一组重载函数中的某一个了:

// 错误: 两个extern "C"函数的名字相同
extern "C" void print(const char*);
extern "C" void print(int)